﻿using System.Collections;
using System.Collections.Generic;
using Core.Extension;
using Core.Mgr._ResMgr;
using UnityEngine;
using Object = UnityEngine.Object;

public enum EAudioSuffix
{
    mp3,
    wav
}

/// <summary>
/// 音频管理器
/// </summary>
public class AudioMgr : Singleton<AudioMgr>
{
    private AudioSource bgSource;
    private GameObject audioObj;
    private bool _isPlaySound = false; //是否在播放相关音乐

    /// <summary>
    /// 判断是否在播放相关的音效，只局限于UnPauseSound和PauseSound
    /// </summary>
    public bool isPlaySound
    {
        get => _isPlaySound;
    }

    /// <summary>
    /// 空闲的AudioSource
    /// </summary>
    private List<AudioSource> idlePool = new List<AudioSource>();

    /// <summary>
    /// 工作中的AudioSource
    /// </summary>
    private List<AudioSource> workPool = new List<AudioSource>();

    /// <summary>
    /// 音效源最大数量
    /// </summary>
    private const int EffectSourceMaxCount = 10;

    private List<Coroutine> _audioEffectCoroutines = new List<Coroutine>();
    private float _soundVolume = 1;

    /// <summary>
    /// 背景音乐音量
    /// </summary>
    public float BGMVolume
    {
        get => bgSource.volume;
        set
        {
            float result = Mathf.Clamp01(value);
            bgSource.volume = result;
        }
    }

    /// <summary>
    /// 全局的音效音量
    /// </summary>
    public float SoundVolume
    {
        get => _soundVolume;
        set
        {
            float result = Mathf.Clamp01(value);
            _soundVolume = result;
            workPool.ForEach(delegate(AudioSource source) { source.volume = _soundVolume; });
            idlePool.ForEach(delegate(AudioSource source) { source.volume = _soundVolume; });
        }
    }

    public void OnInit()
    {
        audioObj = new GameObject("AudioMgr");
        bgSource = audioObj.AddComponent<AudioSource>();
        bgSource.playOnAwake = false;
        for (int i = 0; i < EffectSourceMaxCount; i++)
        {
            AudioSource effectSource = audioObj.AddComponent<AudioSource>();
            effectSource.playOnAwake = false;
            effectSource.volume = _soundVolume;
            effectSource.loop = false;
            idlePool.Add(effectSource);
        }

        SetMuteToEffect(!SetDataModel.AudioEffectOn);
        SetMuteToBGM(!SetDataModel.BGMusicOn);
        Object.DontDestroyOnLoad(audioObj); 
        BGMVolume = 0.09f;
        PlayMusic("BackGroundSound", EAudioSuffix.mp3, true);
    }


    public void PlayMusic(string fullName, EAudioSuffix suffix = EAudioSuffix.mp3, bool isLoop = true)
    {
        ResMgr.LoadAsync<AudioClip>($"Audios/{fullName}.{suffix}", re =>
        {
            if (re != null) PlayMusic(re, isLoop);
        });
    }

    public void PlayMusic(AudioClip audioClip, bool isLoop = true)
    {
        bgSource.clip = audioClip;
        bgSource.Play();
        bgSource.loop = isLoop;
    }

    public void PauseMusic()
    {
        bgSource.Pause();
    }

    public void ResumeMusic()
    {
        if (bgSource.clip != null)
        {
            bgSource.UnPause();
        }
    }

    public void StopMusic()
    {
        if (bgSource != null && bgSource.clip)
        {
            bgSource.Stop();
            bgSource.clip = null;
        }
    }

    /// <summary>
    /// 播放音效
    /// </summary>
    /// <param name="fullName"></param>
    /// <param name="volumeScale">音量</param>
    /// <param name="suffix">相对于全局音量的缩放，0~1</param>
    public void PlaySound(string fullName, EAudioSuffix suffix = EAudioSuffix.mp3, float volumeScale = 1)
    {
        if (!SetDataModel.AudioEffectOn) return;
        ResMgr.LoadAsync<AudioClip>($"Audios/{fullName}.{suffix}", (re) =>
        {
            if (re != null)
            {
                PlaySound(re, volumeScale);
            }
        });
    }

    /// <summary>
    /// 播放音效
    /// </summary>
    public AudioSource PlaySound(AudioClip audioClip, float volumeScale = 1, bool loop = false)
    {
        if (!SetDataModel.AudioEffectOn) return null;
        if (idlePool.Count == 0)
        {
            Debug.LogWarning("播放失败,EffectSource无空闲");
            return null;
        }

        volumeScale = Mathf.Clamp01(volumeScale);
        AudioSource audioSource = idlePool[0];
        audioSource.clip = audioClip;
        audioSource.volume = volumeScale * SoundVolume;
        audioSource.loop = loop;
        audioSource.Play();
        workPool.Add(audioSource);
        idlePool.Remove(audioSource);
        if (!loop)
        {
            float musicLength = audioClip.length;
            Coroutine coroutine = GameRoot.Ins.StartCoroutine(
                DelayCallback(musicLength, audioSource));
            _audioEffectCoroutines.Add(coroutine);
        }

        return audioSource;
    }

    public void PauseSound(AudioSource effectSource)
    {
        if (workPool.Contains(effectSource))
        {
            _isPlaySound = false;
            effectSource.Pause();
        }
    }

    public void UnPauseSound(AudioSource effectSource)
    {
        if (workPool.Contains(effectSource))
        {
            _isPlaySound = true;
            effectSource.UnPause();
        }
    }

    /// 停止音效
    public void StopSound(AudioSource effectSource)
    {
        if (workPool.Contains(effectSource) && effectSource != null)
        {
            effectSource.Stop();
            effectSource.clip = null;
            workPool.Remove(effectSource);
            idlePool.Add(effectSource);
        }
    }

    /// <summary>
    /// 停止所有音效
    /// </summary>
    public void StopAllSound()
    {
        for (int i = 0; i < _audioEffectCoroutines.Count; i++)
        {
            GameRoot.Ins.StopCoroutine(_audioEffectCoroutines[i]);
        }

        _audioEffectCoroutines.Clear();
        int count = workPool.Count;
        for (int i = 0; i < count; i++)
        {
            workPool[0].Stop();
            workPool[0].clip = null;
            idlePool.Add(workPool[0]);
            workPool.RemoveAt(0);
        }
    }

    IEnumerator DelayCallback(float delay, AudioSource audioSource)
    {
        if (delay < 0.5f) delay = 0.5f;
        yield return new WaitForSeconds(delay);
        yield return new WaitUntil(() => !audioSource.isPlaying); //等到当前音频源没有在播放时 
        if (audioSource != null)
        {
            audioSource.clip = null;
            workPool.Remove(audioSource);
            idlePool.Add(audioSource);
        }
    }

    public void SetMuteToBGM(bool isMute)
    {
        bgSource.mute = isMute;
    }

    public void SetMuteToEffect(bool isMute)
    {
        idlePool.ForEach(delegate(AudioSource source) { source.mute = isMute; });
        workPool.ForEach(delegate(AudioSource source) { source.mute = isMute; });
    }
}